package com.own.core.dyn.list;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.Transient;

import org.apache.wicket.AttributeModifier;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;

import com.own.core.dyn.add.AddObjectPanel;
import com.own.core.dyn.search.SimpleSearchPanel;
import com.own.core.html.component.OwnBreadCrumbBar;
import com.own.core.html.component.OwnSortableDaoProvider;
import com.own.core.html.component.link.OwnAjaxLink;
import com.own.core.html.form.Label.OwnLabel;
import com.own.core.html.form.dateField.DateField;
import com.own.core.html.form.dropDown.DropDown;
import com.own.core.html.form.object.ObjectField;
import com.own.core.html.form.textArea.TextArea;
import com.own.core.html.form.textField.TextField;
import com.own.core.html.panel.OwnPanel;
import com.own.core.html.panel.checkBox.OwnSimpleCheckBoxPanel;
import com.own.core.html.panel.link.OwnAjaxLinkPanel;
import com.own.core.html.table.OwnAbstractColumn;
import com.own.core.html.table.OwnAjaxFallbackDefaultDataTable;
import com.own.core.main.Home;
import com.own.core.object.Dao;
import com.own.core.util.Action;
import com.own.core.object.admin.pages.Page;

import com.own.core.object.lookup.Lookup;
import com.own.core.operation.DbOperation;
import com.own.util.Converter;
import com.own.util.FieldUtil;
import com.own.core.util.Mode;
import com.own.util.ObjectUtil;
import com.own.util.ResourceUtil;
import com.own.util.listener.OwnListener;

public class ListObjectPanel extends OwnPanel {
	/**
	 * constructor
	 */

	private String message = "";
	private Home home;

	// using when open modal windows
	@Transient
	private Field field;

	// select field
	private Dao selected;

	private OwnAjaxLink addLink;
	private OwnAjaxLink searchLink;
	private SimpleSearchPanel simpleSearchPanel;
	private OwnAjaxFallbackDefaultDataTable table;

	final private Map<Field, Object> FilterMap = new HashMap<Field, Object>();
	int pageSize = 3;

	public ListObjectPanel(String id, Page page, Home home) {
		super(id);
		setHome(home);

	}

	public ListObjectPanel(Home home) {
		super("content");
		setHome(home);

	}

	public void initPanel() {

		// add header label
		String headerStr = ResourceUtil.getResource(getCls()).getObject()
				.toString();
		if (selected != null) {
			headerStr = headerStr + " ( " + selected.getName() + " ) ";

		}
		setTitle(headerStr);
		OwnLabel headerLabel = new OwnLabel("header", headerStr);
		addOrReplace(headerLabel);

		// simple search panel
		simpleSearchPanel = new SimpleSearchPanel(this);
		simpleSearchPanel.setVisible(false);
		addOrReplace(simpleSearchPanel);

		// add button
		addLink = new OwnAjaxLink("link") {
			@Override
			public void onClick(AjaxRequestTarget target) {
				try {

					AddObjectPanel daoPanel = new AddObjectPanel(
							ListObjectPanel.this);
					Dao dao = (Dao) getCls().newInstance();

					// in case linkable field
					if (selected != null) {
						ObjectUtil.FillObjectWithObject(dao, selected);
					}
					daoPanel.draw(dao);
					home.getModalWindow().setContent(daoPanel);
					home.getModalWindow().show(target);
					setMainComponent(ListObjectPanel.this);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		};

		if (mode == Mode.FULL && haveAuthorization(getCls(), Action.CREATE)) {
			addLink.add(new AttributeModifier("class", true, new Model("Add")));
		}
		addOrReplace(addLink);

		// simple Search button
		searchLink = new OwnAjaxLink("simpleSearch") {

			@Override
			public void onClick(AjaxRequestTarget target) {
				simpleSearchPanel.setVisible(!simpleSearchPanel.isVisible());
				target.addComponent(simpleSearchPanel);

			}
		};
		if (mode == Mode.FULL && haveAuthorization(getCls(), Action.SEARCH)) {
			searchLink.add(new AttributeModifier("class", true, new Model(
					"search")));
		}
		addOrReplace(searchLink);

		pageSize = 100;

		// add message
		addOrReplace(new Label("message", new PropertyModel(this,
				"selectedContactLabel")));

		// draw columes
		List<IColumn> columns = new ArrayList<IColumn>();
		if (mode == Mode.VIEW || getCls().isEnum()) {
			drawCheckBoxSelectionField(columns);
		}

		// get Dao fields
		Field[] fields = getCls().getDeclaredFields();
		if (Lookup.class.isAssignableFrom(getCls())) {
			fields = FieldUtil.getAllFields(getCls());
		}
		for (Field field : fields) {
			if (getCls().isEnum()) {

			} else {
				drawUsingAnnotation(field, columns);
			}
		}

		try {
			// draw controller
			getOwnPage().generateControllerObject().afterRenderList(columns,
					this);
		} catch (Exception e) {

		}
		if (mode == Mode.FULL && haveAuthorization(getCls(), Action.UPDATE)) {

			columns.add(new OwnAbstractColumn("Edit") {
				public void populateItem(Item cellItem, String componentId,
						IModel model) {
					cellItem.add(new EditPanel(componentId, model));
				}
			});
		}
		if (mode == Mode.FULL && haveAuthorization(getCls(), Action.DELETE)) {
			columns.add(new OwnAbstractColumn("Delete") {
				public void populateItem(Item cellItem, String componentId,
						IModel model) {
					cellItem.add(new DeletePanel(componentId, model));
				}
			});
		}

		OwnSortableDaoProvider daoProvider;

		if (getLoadQuery() != null && selected != null) {
			Map map = new HashMap();

			map.put("id", selected.getId());
			daoProvider = new OwnSortableDaoProvider(getLoadQuery(), map);
		} else {

			daoProvider = new OwnSortableDaoProvider(FilterMap, getCls());
		}

		table = new OwnAjaxFallbackDefaultDataTable("table", columns,
				daoProvider, pageSize);

		addOrReplace(table);

	}

	private void drawUsingAnnotation(Field field, List<IColumn> columns) {

		Annotation[] annotations = field.getAnnotations();

		for (Annotation ann : annotations) {

			if (ann instanceof TextField) {
				drawTextField(columns, field, (TextField) ann);

			} else if (ann instanceof ObjectField) {
				if (mode != Mode.FULL) {
					continue;
				}
				drawObjectField(columns, field, (ObjectField) ann);
			} else if (ann instanceof DateField) {
				drawDateField(columns, field, (DateField) ann);

			} else if (ann instanceof TextArea) {
				drawTextArea(columns, field, (TextArea) ann);

			} else if (ann instanceof DropDown) {
				drawDropDown(columns, field, (DropDown) ann);

			}

		}

	}

	private void drawDropDown(List<IColumn> columns, Field field, DropDown ann) {
		if (ann.list()) {
//			if (field.getType().isEnum()) {
				columns.add(new PropertyColumn(ResourceUtil.getResource(field),
						field.getName() + "." + ann.property()));
//			} else {
//				columns.add(new PropertyColumn(ResourceUtil.getResource(field),
//						field.getName() + "." + ann.property()));
//			}
		}
	}

	private void drawTextArea(List<IColumn> columns, Field field, TextArea ann) {
		if (ann.list()) {

			columns.add(new PropertyColumn(ResourceUtil.getResource(field),
					field.getName(), field.getName()));

		}

	}

	private void drawTextField(List<IColumn> columns, Field field, TextField ann) {
		if (!ann.linkable().equals("")) {
			addLinkableField(columns, field, ann.linkable());
		} else if (ann.list()) {
			columns.add(new PropertyColumn(ResourceUtil.getResource(field),
					field.getName(), field.getName()));
		}
	}

	private void drawObjectField(List<IColumn> columns, final Field field,
			final ObjectField ann) {

		if (ann.list()) {

			final Class refCls = FieldUtil.getGenericClass(field);

			columns.add(new OwnAbstractColumn(field) {
				@Override
				public void populateItem(Item item, String componentId,
						IModel rowModel) {

					OwnAjaxLinkPanel ownAjaxLinkPanel = new OwnAjaxLinkPanel(
							componentId, getDisplayModel());
					if (ann.iconSupport()) {
						ownAjaxLinkPanel.setCssClass(refCls);
					}
					try {
						field.setAccessible(true);
						ownAjaxLinkPanel.setTitle(Converter.convertToString(field
								.get(rowModel.getObject())));
					} catch (Exception e) {
						e.printStackTrace();
					}

					ownAjaxLinkPanel.addOwnListener(new OwnListener(rowModel) {
						public void execute(AjaxRequestTarget target) {

							Home selectHome = new Home("content", new Page(
									refCls));
							selectHome.setMode(ann.mode());
							ListObjectPanel listPanel = new ListObjectPanel(
									selectHome);
							selectHome.setListPanel(listPanel);
							selectHome.getListPanel().setSelected(
									(Dao) this.model.getObject());
							selectHome.getListPanel().setField(field);
							selectHome.initPanel();
							home.getModalWindow().setContent(selectHome);
							home.getModalWindow().show(target);
						}
					});

					item.add(ownAjaxLinkPanel);
				}
			});

		}
	}

	private void addLinkableField(List<IColumn> columns, final Field field,
			final String linkable) {

		final Class refCls = FieldUtil.getGenericClass(field);

		columns.add(new OwnAbstractColumn(field) {
			@Override
			public void populateItem(Item item, String componentId,
					IModel rowModel) {

				OwnAjaxLinkPanel ownAjaxLinkPanel = new OwnAjaxLinkPanel(
						componentId, rowModel);

				try {
					columeField.setAccessible(true);
					ownAjaxLinkPanel = new OwnAjaxLinkPanel(componentId,
							ResourceUtil.getResourceString(Converter
									.convertToString(columeField.get(rowModel
											.getObject()))));

				} catch (Exception e) {
					e.printStackTrace();
				}

				ownAjaxLinkPanel.addOwnListener(new OwnListener(rowModel) {
					public void execute(AjaxRequestTarget target) {

						try {
							Dao dao = (Dao) model.getObject();
							Class cls = FieldUtil.getGenericClass(getCls()
									.getDeclaredField(linkable));
							ListObjectPanel listObj = new ListObjectPanel(
									ListObjectPanel.this.home);
							listObj.setSelected(dao);
							listObj.setOwnPage(cls);
							// generate query name

							String queryName = cls.getSimpleName()
									.toLowerCase()
									+ ".listBy"
									+ dao.getClass().getSimpleName();
							listObj.setLoadQuery(queryName);
							listObj.initPanel();
							getBreadCrumbModel().setActive(listObj);
							((OwnBreadCrumbBar) getBreadCrumbModel())
									.setVisible(true);
							ListObjectPanel.this.home
									.addOrReplace((OwnBreadCrumbBar) getBreadCrumbModel());
							ListObjectPanel.this.home.addOrReplace(listObj);

							target.addComponent(ListObjectPanel.this.home);
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				});

				item.add(ownAjaxLinkPanel);
			}
		});
	}

	private void drawDateField(List<IColumn> columns, Field field, DateField ann) {
		if (ann.list()) {
			columns.add(new PropertyColumn(ResourceUtil.getResource(field),
					field.getName(), field.getName()));
		}
	}

	public String getSelectedContactLabel() {
		String temp = message;
		message = "";
		return temp;
	}

	private void drawCheckBoxSelectionField(List<IColumn> columns) {

		columns.add(new OwnAbstractColumn("") {
			@Override
			public void populateItem(Item item, String componentId,
					IModel rowModel) {

				OwnSimpleCheckBoxPanel ownSimpleCheckBoxPanel = new OwnSimpleCheckBoxPanel(
						componentId, rowModel, selected, field);

				item.add(ownSimpleCheckBoxPanel);
			}
		});

	}

	/**
	     * 
	     */
	class DeletePanel extends Panel {
		/**
		 * @param id
		 *            component id
		 * @param model
		 *            model for contact
		 */
		public DeletePanel(String id, IModel model) {
			super(id, model);
			add(new OwnAjaxLink() {

				@Override
				public void onClick(AjaxRequestTarget target) {
					DbOperation.getME().delete(
							(Dao) getParent().getDefaultModelObject());
					message = "delete succesful";
					target.addComponent(table);

				}
			});
		}
	}

	class EditPanel extends Panel {
		/**
		 * @param id
		 *            component id
		 * @param model
		 *            model for contact
		 */
		public EditPanel(String id, IModel model) {
			super(id, model);
			add(new OwnAjaxLink() {
				public void onClick(AjaxRequestTarget target) {
					AddObjectPanel daoPanel = new AddObjectPanel(
							ListObjectPanel.this);

					daoPanel.draw((Dao) getParent().getDefaultModelObject());
					home.getModalWindow().setContent(daoPanel);
					home.getModalWindow().show(target);

					setMainComponent(ListObjectPanel.this);

				}
			});
		}
	}

	/**
	 * @return selected contact
	 */
	public Dao getSelected() {
		return selected;
	}

	/**
	 * sets selected contact
	 * 
	 * @param selected
	 */
	public void setSelected(Dao selected) {
		addStateChange();
		this.selected = selected;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public OwnAjaxFallbackDefaultDataTable getTable() {
		return table;
	}

	public void setTable(OwnAjaxFallbackDefaultDataTable table) {
		this.table = table;
	}

	public void addFilter(Field field, Object value) {
		FilterMap.put(field, value);
	}

	public void clearFilterMap() {
		FilterMap.clear();
	}

	public Home getHome() {
		return home;
	}

	public void setHome(Home home) {
		setParentPanel(home);
		this.home = home;
	}

	public Field getField() {
		return field;
	}

	public int getPageSize() {
		return pageSize;
	}

	public void setField(Field field) {
		this.field = field;
	}

	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

}
